//
//  NSURLSessionTask+operation.m
//  nbUtil
//
//  Created by 相颖 on 16/7/11.
//  Copyright © 2016年 相颖. All rights reserved.
//

#import "NSURLSessionTask+operation.h"
#import <objc/runtime.h>

static const void *operationKey = &operationKey;
static const char *NSURLSessionTaskCancelBlockKey = "NSURLSessionTaskCancelBlockKey";
static const char *KLURLSessionTask_requestId = "KLURLSessionTask_requestId";

@implementation NSURLSessionTask (operation)
@dynamic operation;
@dynamic cancelBlock;

+ (void)load{
    //ios7的datarequest并非该类，所以替换方法不会进
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self operationReplace];
        [self cancelReplace];
    });
}

#pragma mark - operation

+ (void)operationReplace{
    objc_property_attribute_t type = { "T", "@\"AFHTTPRequestOperation\"" };
    objc_property_attribute_t ownership = { "&", "N" }; // C = copy  & = strong
    objc_property_attribute_t backingivar  = { "V", "_operation" };
    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    class_addProperty(objc_getClass("__NSCFLocalDataTask"), "operation", attrs, 3);
    class_addMethod(objc_getClass("__NSCFLocalDataTask"), @selector(operation), (IMP)operationGetter, "@@:");
    class_addMethod(objc_getClass("__NSCFLocalDataTask"), @selector(setOperation:), (IMP)operationSetter, "v@:@");
    
    class_addProperty(objc_getClass("__NSCFLocalDownloadTask"), "operation", attrs, 3);
    class_addMethod(objc_getClass("__NSCFLocalDownloadTask"), @selector(operation), (IMP)operationGetter, "@@:");
    class_addMethod(objc_getClass("__NSCFLocalDownloadTask"), @selector(setOperation:), (IMP)operationSetter, "v@:@");
    
    class_addProperty(objc_getClass("__NSCFBackgroundDataTask"), "operation", attrs, 3);
    class_addMethod(objc_getClass("__NSCFBackgroundDataTask"), @selector(operation), (IMP)operationGetter, "@@:");
    class_addMethod(objc_getClass("__NSCFBackgroundDataTask"), @selector(setOperation:), (IMP)operationSetter, "v@:@");
    
    class_addProperty(objc_getClass("__NSCFBackgroundDownloadTask"), "operation", attrs, 3);
    class_addMethod(objc_getClass("__NSCFBackgroundDownloadTask"), @selector(operation), (IMP)operationGetter, "@@:");
    class_addMethod(objc_getClass("__NSCFBackgroundDownloadTask"), @selector(setOperation:), (IMP)operationSetter, "v@:@");
}

AFHTTPRequestOperation *operationGetter(id self, SEL _cmd) {
//    Ivar ivar = class_getInstanceVariable(objc_getClass("__NSCFLocalDataTask"), "_operation");
//    AFHTTPRequestOperation *operation = object_getIvar(self, ivar);
    AFHTTPRequestOperation *operation = objc_getAssociatedObject(self,operationKey);
    if (operation == nil) {
        operation = [[AFHTTPRequestOperation alloc] initWithTask:self];
        objc_setAssociatedObject(self, operationKey, operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//        object_setIvar(self, ivar, operation);
    }
    return operation;
}

void operationSetter(id self, SEL _cmd, AFHTTPRequestOperation *newName) {
//    Ivar ivar = class_getInstanceVariable(objc_getClass("__NSCFLocalDataTask"), "_operation");
//    object_setIvar(self, ivar, newName);
    objc_setAssociatedObject(self, operationKey, newName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    newName.sessionTask = self;
}

#pragma mark - cancel

+ (void)cancelReplace{
    //这么写是为了奇葩的ios7.x系统，7.x的dataTask父类不是urlsessionTask类，会报错说localdatatask没有这个属性
    //cancelblock
    objc_property_attribute_t type = { "T", "@\"NSURLSessionTaskCancelBlock\"" };
    objc_property_attribute_t ownership = { "C", "N" }; // C = copy  & = strong
    objc_property_attribute_t backingivar  = { "V", "_cancelBlock" };
    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    class_addProperty(objc_getClass("__NSCFLocalDataTask"), "cancelBlock", attrs, 3);
    class_addMethod(objc_getClass("__NSCFLocalDataTask"), @selector(cancelBlock), (IMP)cancelBlockGetter, "@@:");
    class_addMethod(objc_getClass("__NSCFLocalDataTask"), @selector(setCancelBlock:), (IMP)cancelBlockSetter, "v@:@");
    
    class_addProperty(objc_getClass("__NSCFLocalDownloadTask"), "cancelBlock", attrs, 3);
    class_addMethod(objc_getClass("__NSCFLocalDownloadTask"), @selector(cancelBlock), (IMP)cancelBlockGetter, "@@:");
    class_addMethod(objc_getClass("__NSCFLocalDownloadTask"), @selector(setCancelBlock:), (IMP)cancelBlockSetter, "v@:@");
    
    class_addProperty(objc_getClass("__NSCFBackgroundDataTask"), "cancelBlock", attrs, 3);
    class_addMethod(objc_getClass("__NSCFBackgroundDataTask"), @selector(cancelBlock), (IMP)cancelBlockGetter, "@@:");
    class_addMethod(objc_getClass("__NSCFBackgroundDataTask"), @selector(setCancelBlock:), (IMP)cancelBlockSetter, "v@:@");
    
    class_addProperty(objc_getClass("__NSCFBackgroundDownloadTask"), "cancelBlock", attrs, 3);
    class_addMethod(objc_getClass("__NSCFBackgroundDownloadTask"), @selector(cancelBlock), (IMP)cancelBlockGetter, "@@:");
    class_addMethod(objc_getClass("__NSCFBackgroundDownloadTask"), @selector(setCancelBlock:), (IMP)cancelBlockSetter, "v@:@");
    
    //nbcancel:
    class_addMethod(objc_getClass("__NSCFLocalDataTask"), @selector(nbCancel:), (IMP)nbcancelSetter, "v@:@");
    class_addMethod(objc_getClass("__NSCFLocalDownloadTask"), @selector(nbCancel:), (IMP)nbcancelSetter, "v@:@");
    class_addMethod(objc_getClass("__NSCFBackgroundDataTask"), @selector(nbCancel:), (IMP)nbcancelSetter, "v@:@");
}

NSURLSessionTaskCancelBlock cancelBlockGetter(id self, SEL _cmd) {
    NSURLSessionTaskCancelBlock cancelBlock = objc_getAssociatedObject(self,NSURLSessionTaskCancelBlockKey);
    return cancelBlock;
}

void cancelBlockSetter(id self, SEL _cmd, NSURLSessionTaskCancelBlock cancelBlock) {
    objc_setAssociatedObject(self, NSURLSessionTaskCancelBlockKey, cancelBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

void nbcancelSetter(id self, SEL _cmd, NSURLSessionTaskCancelBlock cancelBlock) {
    objc_setAssociatedObject(self, NSURLSessionTaskCancelBlockKey, cancelBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
    if ([(NSURLSessionTask*)self state] == NSURLSessionTaskStateRunning) {
        [self cancel];
    }else{
        if (cancelBlock) {
            cancelBlock();
            [self setCancelBlock:nil];
        }
    }
}

- (void)nbCancel:(void (^)(void))completionHandler{
    
}

- (void)setRequestId:(NSString *)requestId {
    objc_setAssociatedObject(self, KLURLSessionTask_requestId, requestId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)requestId {
    return objc_getAssociatedObject(self, KLURLSessionTask_requestId);
}

@end
